//=======================================================
//  RGB Data Output Interface 
//=======================================================
module rgb_output(
	// Internal Control Signals //
	 input 		          		iclk
    ,input                      reset_n
    ,input      [11 -1: 0]      weight_in  //2047>1920
    ,input      [11 -1: 0]      height_in  //2047>1080
    // From rgb_input module
    ,input                      hs_switch_req
    ,output reg                 hs_switch_ack

    ,input                      vs_pos_pulse
    // RGB RAM Interface
    ,output reg [12 -1: 0]      rgb_raddr
    ,input      [24 -1: 0]      rgb_rdata
    // Bicubic output Interface
    ,output reg                 rgb_frame
    ,output reg                 rgb_read_valid
    ,output reg [24 -1: 0]      rgb_rdata_out
    ,output reg [11 -1: 0]      linePix_count
);

//=======================================================
//  Local parametr 
//=======================================================
localparam      RAM0_BASE = 0;
localparam      RAM1_BASE = 2048;

//=======================================================
//  REG/WIRE declarations
//=======================================================
reg                     hs_switch_req_d;
reg                     hs_switch_req_d1;
reg                     hs_switch_req_d2;
reg                     hs_switch_req_d3;


reg     [11 -1: 0]      linePix_addr;
reg     [11 -1: 0]      line_count; //2047
reg     [12 -1: 0]      base_addr; //4095

reg     [11 -1: 0]      weight;  //2047>1920
reg     [11 -1: 0]      height;  //2047>1080

reg                     read_enable;
reg                     read_address_en;
reg                     read_enable_d1;
reg                     read_data_en;

//=======================================================
//  Structural coding
//=======================================================
// register the frame height and weight at the vs_posPluse.
always@(posedge iclk or negedge reset_n)
begin
  if (!reset_n) begin
    weight <= 0;
    height <= 0;
//  end else if(vs_posPluse) begin
  end else begin
    weight <= weight_in;
    height <= height_in;
  end
end

//-- generate hs_switch_ack signal
always@(posedge iclk or negedge reset_n)
begin
  if (!reset_n) begin
    hs_switch_req_d <= 0;
    hs_switch_req_d1 <= 0;
    hs_switch_req_d2 <= 0;
    hs_switch_req_d3 <= 0;
  end else begin
    hs_switch_req_d <= hs_switch_req ;
    hs_switch_req_d1 <= hs_switch_req_d;
    hs_switch_req_d2 <= hs_switch_req_d1;
    hs_switch_req_d3 <= hs_switch_req_d2;
  end
end

always@(posedge iclk or negedge reset_n)
begin
  if (!reset_n) begin
    hs_switch_ack <= 0;
  end else if (hs_switch_req_d2 & (!hs_switch_req_d3)) begin
    hs_switch_ack <= 0;  //Last two cycle
  end else if (hs_switch_req_d) begin
    hs_switch_ack <= 1;
  end
end

//-- generate the switch_pluse
assign hs_switch_pulse = hs_switch_req_d & (!hs_switch_req_d1);

always@(posedge iclk or negedge reset_n)
begin
  if (!reset_n) begin
    read_enable <= 0;
  end else if (linePix_addr == (weight -1)) begin
    read_enable <= 0;
  end else if (hs_switch_pulse) begin
    read_enable <= 1;
  end
end

always@(posedge iclk or negedge reset_n)
begin
  if (!reset_n) begin
    read_address_en<= 0;
    read_enable_d1 <= 0;
    read_data_en   <= 0;
  end else begin
    read_address_en<= read_enable;
    read_enable_d1 <= read_address_en;
    read_data_en   <= read_enable_d1;
  end
end
assign read_data_posPulse = read_data_en & (!rgb_read_valid);

//-- counter the input RGB data number
always@(posedge iclk or negedge reset_n)
begin
  if (!reset_n) begin
    linePix_addr <= 0;
  end else if (linePix_addr == (weight -1)) begin
    linePix_addr <= 0;
  end else if (read_enable) begin
    linePix_addr <= linePix_addr + 1'b1;
  end
end

//-- counter the hs line number
always@(posedge iclk or negedge reset_n)
begin
  if (!reset_n) begin
    line_count <= 0;
  end else if ((vs_pos_pulse) 
           || ((line_count == (height -1)) && (linePix_addr == (weight -1)))) begin
    line_count <= 0;
  end else if (linePix_addr == (weight -1)) begin
//  end else if (hs_switch_pulse) begin
    line_count <= line_count + 1'b1;
  end
end

//-- generete the base_addr
always@(posedge iclk or negedge reset_n)
begin
  if (!reset_n) begin
    base_addr <= RAM0_BASE;
  end else if (line_count[0] == 1'b0) begin
    base_addr <= RAM0_BASE;
  end else if (line_count[0] == 1'b1) begin
    base_addr <= RAM1_BASE;
  end
end

//-- generate the rgb ram interface
always@(posedge iclk or negedge reset_n)
begin
  if (!reset_n) begin
    rgb_raddr <= 0;
  end else if (read_address_en) begin
    rgb_raddr  <= {base_addr + linePix_addr};
  end else begin
    rgb_raddr <= base_addr;
  end
end

always@(posedge iclk or negedge reset_n)
begin
  if (!reset_n) begin
    rgb_rdata_out <= 0;
    rgb_read_valid <= 0;
  end else if (read_data_en) begin
    rgb_rdata_out <= rgb_rdata;
    rgb_read_valid <= 1;
  end else begin
    rgb_rdata_out <= 0;
    rgb_read_valid <= 0;
  end
end

always@(posedge iclk or negedge reset_n)
begin
  if (!reset_n) begin
    rgb_frame <= 0;
  end else if (read_data_posPulse && (line_count == 0)) begin
    rgb_frame <= 1;
  end else begin
    rgb_frame <= 0;
  end
end

always@(posedge iclk or negedge reset_n)
begin
  if (!reset_n) begin
    linePix_count <= 0;
  end else if (linePix_count == (weight -1)) begin
    linePix_count <= 0;
  end else if (rgb_read_valid) begin
    linePix_count <= linePix_count + 1;
  end else begin
    linePix_count <= 0;
  end
end

endmodule

